iT邦幫忙

2022 iThome 鐵人賽

DAY 12
0
自我挑戰組

挑戰typescript+react+golang+graphql系列 第 12

Day12.Graphql Schema,Type

  • 分享至 

  • xImage
  •  

Schema 和類型
在本頁,你將學到關於 GraphQL 類型系統中所有你需要瞭解的知識,以及類型系統如何描述可以查詢的數據。因為 GraphQL 可以運行在任何後端框架或者編程語言之上,我們將摒除實現上的細節而僅僅專註於其概念。

類型系統(Type System)
如果你之前見到過 GraphQL 查詢,你就知道 GraphQL 查詢語言基本上就是關於選擇對象上的欄位。因此,例如在下列查詢中:

{
  hero {
    name
    appearsIn
  }
}
{
  "data": {
    "hero": {
      "name": "R2-D2",
      "appearsIn": [
        "NEWHOPE",
        "EMPIRE",
        "JEDI"
      ]

我們以一個特殊的對象 "root" 開始
選擇其上的 hero 欄位
對於 hero 返回的對象,我們選擇 name 和 appearsIn 欄位
因為一個 GraphQL 查詢的結構和結果非常相似,因此即便不知道服務器的情況,你也能預測查詢會返回什麼結果。但是一個關於我們所需要的數據的確切描述依然很有意義,我們能選擇什麼欄位?服務器會返回哪種對象?這些對象下有哪些欄位可用?這便是引入 schema 的原因。

每一個 GraphQL 服務都會定義一套類型,用以描述你可能從那個服務查詢到的數據。每當查詢到來,服務器就會根據 schema 驗證並執行查詢。

類型語言(Type Language)
GraphQL 服務可以用任何語言編寫,因為我們並不依賴於任何特定語言的句法句式(譬如 JavaScript)來與 GraphQL schema 溝通,我們定義了自己的簡單語言,稱之為 “GraphQL schema language” —— 它和 GraphQL 的查詢語言很相似,讓我們能夠和 GraphQL schema 之間可以無語言差異地溝通。

對象類型和欄位(Object Types and Fields)
一個 GraphQL schema 中的最基本的組件是對象類型,它就表示你可以從服務上獲取到什麼類型的對象,以及這個對象有什麼欄位。使用 GraphQL schema language,我們可以這樣表示它:

type Character {
  name: String!
  appearsIn: [Episode!]!
}

Character 是一個 GraphQL 對象類型,表示其是一個擁有一些欄位的類型。你的 schema 中的大多數類型都會是對象類型。
name 和 appearsIn 是 Character 類型上的欄位。這意味著在一個操作 Character 類型的 GraphQL 查詢中的任何部分,都只能出現 name 和 appearsIn 欄位。
String 是內置的標量類型之一 —— 標量類型是解析到單個標量對象的類型,無法在查詢中對它進行次級選擇。後面我們將細述標量類型。
String! 表示這個欄位是非空的,GraphQL 服務保證當你查詢這個欄位後總會給你返回一個值。在類型語言裡面,我們用一個感嘆號來表示這個特性。
[Episode!]! 表示一個 Episode 數組。因為它也是非空的,所以當你查詢 appearsIn 欄位的時候,你也總能得到一個數組(零個或者多個元素)。且由於 Episode! 也是非空的,你總是可以預期到數組中的每個項目都是一個 Episode 對象。
現在你知道一個 GraphQL 對象類型看上去是怎樣,也知道如何閱讀基礎的 GraphQL 類型語言了。

參數(Arguments)
GraphQL 對象類型上的每一個欄位都可能有零個或者多個參數,例如下麵的 length 欄位:

type Starship {
id: ID!
name: String!
length(unit: LengthUnit = METER): Float
}
所有參數都是具名的,不像 JavaScript 或者 Python 之類的語言,函數接受一個有序參數列表,而在 GraphQL 中,所有參數必須具名傳遞。本例中,length 欄位定義了一個參數,unit。

參數可能是必選或者可選的,當一個參數是可選的,我們可以定義一個默認值 —— 如果 unit 參數沒有傳遞,那麼它將會被默認設置為 METER。

查詢和變更類型(The Query and Mutation Types)
你的 schema 中大部分的類型都是普通對象類型,但是一個 schema 內有兩個特殊類型:


schema {
  query: Query
  mutation: Mutation
}

每一個 GraphQL 服務都有一個 query 類型,可能有一個 mutation 類型。這兩個類型和常規對象類型無差,但是它們之所以特殊,是因為它們定義了每一個 GraphQL 查詢的入口。因此如果你看到一個像這樣的查詢:

query {
  hero {
    name
  }
  droid(id: "2000") {
    name
  }
}
{
  "data": {
    "hero": {
      "name": "R2-D2"
    },
    "droid": {
      "name": "C-3PO"
    }
  }
}

那表示這個 GraphQL 服務需要一個 Query 類型,且其上有 hero 和 droid 欄位:

type Query {
  hero(episode: Episode): Character
  droid(id: ID!): Droid
}

Mutation也是類似的方式 —— 你在 Mutation 類型上定義一些欄位,然後這些欄位將作為 mutation 根欄位使用,接著你就能在你的查詢中調用。

有必要記住的是,除了作為 schema 的入口,Query 和 Mutation 類型與其它 GraphQL 對象類型別無二致,它們的欄位也是一樣的工作方式。

標量類型(Scalar Types)
一個對象類型有自己的名字和欄位,而某些時候,這些欄位必然會解析到具體數據。這就是標量類型的來源:它們表示對應 GraphQL 查詢的葉子節點。

下列查詢中,name 和 appearsIn 欄位將解析到標量類型:

{
  hero {
    name
    appearsIn
  }
}
{
  "data": {
    "hero": {
      "name": "R2-D2",
      "appearsIn": [
        "NEWHOPE",
        "EMPIRE",
        "JEDI"
      ]
    }
  }
}

我們知道這些欄位沒有任何次級欄位 —— 因為讓它們是查詢的葉子節點。

GraphQL 自帶一組默認標量類型:

Int:有符號 32 位整數。
Float:有符號雙精度浮點值。
String:UTF‐8 字元序列。
Boolean:true 或者 false。
ID:ID 標量類型表示一個唯一標識符,通常用以重新獲取對象或者作為緩存中的鍵。ID 類型使用和 String 一樣的方式序列化;然而將其定義為 ID 意味著並不需要人類可讀型。
大部分的 GraphQL 服務實現中,都有自定義標量類型的方式。例如,我們可以定義一個 Date 類型:

scalar Date
然後就取決於我們的實現中如何定義將其序列化、反序列化和驗證。例如,你可以指定 Date 類型應該總是被序列化成整型時間戳,而客戶端應該知道去要求任何 date 欄位都是這個格式。


上一篇
Day 11 Graphql Query, Mutation
下一篇
Day13.Reflect
系列文
挑戰typescript+react+golang+graphql18
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言